﻿///////////////////////////////////////////////////////////////////////////////
/// Copyright (c) by longshuang@msn.cn 2014.
/// All rights reserved.
/// 
/// @File	: Engine.Memory.hpp
/// @Brief	: 内存管理对象集
/// @Author	: Leo Zhao <longshuang@msn.cn>
/// @Date	: 2014-12-10
///
/// CHANGELOG
///		2014-12-22	增加线程安全的Buffer及双缓冲的DoubleBuffer
///		2014-12-10	增加对象内存池
///////////////////////////////////////////////////////////////////////////////
#ifndef		__ENGINE_MEMORY_HPP_INCLUDE__
#define		__ENGINE_MEMORY_HPP_INCLUDE__

#include	<atomic>
#include	<cstdint>
#include	<cstring>
#include	<cstdlib>
#include	<list>
#include	<thread>
#include	<mutex>

/// 本命名空间内的类不推荐外部使用
namespace Engine { namespace Memory { namespace _Private {
	class Block {
	public:
		struct Node {
			bool	bUsed;
			Node *	pPrev;
			Node *	pNext;
		};

	public:
		Block() : pHead(NULL) {
			pHead = new Node;
			pHead->bUsed = true;
			pHead->pPrev = pHead;
			pHead->pNext = pHead;
		}

		virtual ~Block() {
			delete pHead;
		}

		/// @Brief	: 在指定节点后增加一个节点
		/// @Param	: pTarget	要插入的节点对象指针
		/// @Param	: pAfter	插入的位置
		/// @Return	: NONE
		inline void		Insert(Node * pTarget, Node * pAfter) {
			pTarget->pNext = pAfter->pNext;
			pTarget->pPrev = pAfter;
			pTarget->pNext->pPrev = pTarget;
			pAfter->pNext = pTarget;
		}

		/// @Brief	: 删除一个节点
		/// @Param	: pNode		节点对象指针
		/// @Return	: NONE
		inline void		Remove(Node * pNode) {
			pNode->pNext->pPrev = pNode->pPrev;
			pNode->pPrev->pNext = pNode->pNext;
		}

	public:
		Node *		pHead;

	};
}}}

namespace Engine { namespace Memory {
		
	/// @Brief	: 对象内存池（非线程安全版本）
	template<class Type>
	class ObjectPool {
	public:
		ObjectPool(size_t nMaxAlloc, size_t nPerAlloc)
			: _nMaxAlloc(nMaxAlloc)
			, _nPerAlloc(nPerAlloc)
			, _nHasAlloc(0) 
			, _pMemory(new _Private::Block()) {
			_Alloc();
		}

		virtual ~ObjectPool() {
			FreeAll();

			for (auto it = _lAllocMemory.begin(); it != _lAllocMemory.end(); ++it)
				std::free(*it);

			delete _pMemory;
		}

		/// @Brief	: 使用内存池构建对象
		/// @Param	: args ...	Type的构造函数需要的参数
		/// @Return	: 申请的地址，如果未申请成功，返回nullptr
		template<typename ... Args>
		Type *		Alloc(Args ... args) {
			if (_pMemory->pHead->pNext->bUsed) {
				if (_nHasAlloc >= _nMaxAlloc || !_Alloc()) 
					return nullptr;
			}

			_Private::Block::Node * pNode = _pMemory->pHead->pNext;
			_pMemory->Remove(pNode);
			_pMemory->Insert(pNode, _pMemory->pHead->pPrev);
			
			pNode->bUsed = true;

			char * pAddr = reinterpret_cast<char *>(pNode);
			Type * pObj = reinterpret_cast<Type *>(pAddr + sizeof(_Private::Block::Node));

			return new (pObj) Type(args...);
		}

		/// @Brief	: 回收申请的内存，将会回调Type的析构函数
		/// @Param	: pObj		通过Malloc申请的内存
		/// @Return	: NONE
		void		Free(Type * pObj) {
			if (!pObj) return;

			pObj->~Type();			
			::memset(pObj, 0, sizeof(Type));

			char * pAddr = reinterpret_cast<char *>(pObj);
			_Private::Block::Node * pNode = reinterpret_cast<_Private::Block::Node *>(pAddr - sizeof(_Private::Block::Node));
			pNode->bUsed = false;
			_pMemory->Remove(pNode);
			_pMemory->Insert(pNode, _pMemory->pHead);
		}

		/// @Brief	: 强制回收所有已分配的资源，慎用
		/// @Param	: NONE
		/// @Return	: NONE
		void		FreeAll() {
			_Private::Block::Node * pNode = _pMemory->pHead->pPrev;

			while (pNode->bUsed && pNode != _pMemory->pHead) {
				char * pAddr = reinterpret_cast<char *>(pNode);
				Type * pObj = reinterpret_cast<Type *>(pAddr + sizeof(_Private::Block::Node));
				pObj->~Type();
				::memset(pObj, 0, sizeof(Type));
				pNode->bUsed = false;
				pNode = pNode->pPrev;
			}
		}

	protected:
		bool		_Alloc() {
			void * pMemory = std::malloc((sizeof(_Private::Block::Node) + sizeof(Type)) * _nPerAlloc);
			if (!pMemory) return false;

			char * pCurrent = reinterpret_cast<char *>(pMemory);
			_nHasAlloc += _nPerAlloc;

			for (size_t nCount = 0; nCount < _nPerAlloc; ++nCount) {
				_Private::Block::Node * pNode = reinterpret_cast<_Private::Block::Node *>(pCurrent);
				pNode->bUsed = false;
				_pMemory->Insert(pNode, _pMemory->pHead);
				pCurrent += sizeof(_Private::Block::Node) + sizeof(Type);
			}
			
			_lAllocMemory.push_back(pMemory);
						
			return true;
		}

	protected:
		size_t				_nMaxAlloc;
		size_t				_nPerAlloc;
		size_t				_nHasAlloc;
		_Private::Block *	_pMemory;
		std::list<void *>	_lAllocMemory;
	};

	/// @Brief	: 对象内存池（线程安全版本）。
	template<class Type>
	class SafeObjectPool : public ObjectPool<Type> {
		typedef ObjectPool<Type>	BasePool;

	public:
		SafeObjectPool(size_t nMaxAlloc, size_t nPerAlloc)
			: BasePool::ObjectPool(nMaxAlloc, nPerAlloc) {
		}

		virtual ~SafeObjectPool() {
			std::unique_lock<std::mutex> iAuto(_iLock);
		}

		/// @Brief	: 使用内存池构建对象
		/// @Param	: args ...	Type的构造函数需要的参数
		/// @Return	: 申请的地址，如果未申请成功，返回nullptr
		template<typename ... Args>
		Type *		Alloc(Args ... args) {
			Type * pObj = nullptr;

			{
				std::unique_lock<std::mutex> iAuto(_iLock);

				if (BasePool::_pMemory->pHead->pNext->bUsed) {
					if (BasePool::_nHasAlloc >= BasePool::_nMaxAlloc || !BasePool::_Alloc())
						return nullptr;
				}

				_Private::Block::Node * pNode = BasePool::_pMemory->pHead->pNext;
				BasePool::_pMemory->Remove(pNode);
				BasePool::_pMemory->Insert(pNode, BasePool::_pMemory->pHead->pPrev);

				pNode->bUsed = true;
				char * pAddr = reinterpret_cast<char *>(pNode);
				pObj = reinterpret_cast<Type *>(pAddr + sizeof(_Private::Block::Node));
			}
			
			return new (pObj) Type(args...);
		}

		/// @Brief	: 回收申请的内存，将会回调Type的析构函数
		/// @Param	: pObj		通过Malloc申请的内存
		/// @Return	: NONE
		void		Free(Type * pObj) {
			if (!pObj) return;

			pObj->~Type();			
			::memset(pObj, 0, sizeof(Type));

			char * pAddr = reinterpret_cast<char *>(pObj);
			_Private::Block::Node * pNode = reinterpret_cast<_Private::Block::Node *>(pAddr - sizeof(_Private::Block::Node));
			pNode->bUsed = false;

			std::unique_lock<std::mutex> iAuto(_iLock);
			BasePool::_pMemory->Remove(pNode);
			BasePool::_pMemory->Insert(pNode, BasePool::_pMemory->pHead);
		}

	private:
		std::mutex			_iLock;
	};
	
	/// @Brief	: 一个简单的读写双Buffer，适用于读写分别处于不同线程且读、写线程均只有一个
	class RWBuffer {
	public:
		RWBuffer(uint32_t nMaxSize) : _bCurWrite(0), _nMaxSize(nMaxSize) {
			_pMem[0] = new char[nMaxSize + sizeof(uint32_t)];
			_pMem[1] = new char[nMaxSize + sizeof(uint32_t)];
			_nMaxSize = nMaxSize;
		}

		virtual ~RWBuffer() {
			delete[] _pMem[0];
			delete[] _pMem[1];
		}

		/// @Brief	: 向Buffer中写数据
		/// @Param	: pData		数据的头地址
		/// @Param	: nSize		数据的大小
		/// @Return	: 是否成功写入数据
		bool	Write(void * pData, size_t nSize) {
			char * pMem = _pMem[_bCurWrite];
			uint32_t * pOffset = (uint32_t *)pMem;
			if ((*pOffset) + nSize > _nMaxSize) return false;
			::memcpy(pMem + sizeof(uint32_t) + (*pOffset), pData, nSize);
			(*pOffset) = (*pOffset) + nSize;
			return true;
		}

		/// @Brief	: 读取数据（这里只是交换一下读写缓冲，并将之前写入的东西头地址返回）
		/// @Param	: NONE
		/// @Return	: 之前写Buffer中数据头地址
		/// @Note	: 地址中的第一个为Uint32_t类型数据，记录了之前写入数据的总大小
		char *	Read() {
			int nPrev = _bCurWrite;
			::memset(_pMem[!nPrev], 0, _nMaxSize);
			_bCurWrite.exchange(!nPrev);
			return _pMem[nPrev];
		}

	private:
		std::atomic<bool>		_bCurWrite;
		uint32_t				_nMaxSize;
		char *					_pMem[2];
	};

} }

#endif//!	__ENGINE_MEMORY_HPP_INCLUDE__
